package com.bestcem.xm.ticket.util;

import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.ticket.constant.Constants;
import com.bestcem.xm.ticket.dao.TicketRecordDao;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketRecord;
import com.bestcem.xm.ticket.enums.TicketRecordEventEnum;
import com.bestcem.xm.ticket.grpc.client.dto.deliver.DeliverAgainTaskDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 二次投放检查工具类
 * @author jy.zhao
 * @version 1.0
 * @date 2021/8/26 12:35
 **/
@Slf4j
@Component
public class DeliverAgainCheckUtil {

    /**
     * 工单状态字段名
     */
    private static final String TICKET_STATUS = "status";

    @Resource
    private TicketRecordDao ticketRecordDao;

    /**
     * 检查二次投放任务的条件是否成立，返回成立的任务id
     * @param ticket 工单
     * @param scene 调用该函数的场景
     *               0: 工单状态变更调用，工单状态变更调用时，条件中要是全部满足的情况，只要出现新增跟进记录，即不成立
     *               1: 提交跟进记录调用
     * @param callTime 调用时间
     * @param deliverAgainTaskDTOList 二次投放任务
     * @return List<DeliverAgainTaskDTO> 符合条件的二次投放任务
     * @author jy.zhao
     * @date 2021/8/24 15:45
     **/
    public List<DeliverAgainTaskDTO> checkDeliverAgainCondition(Ticket ticket, Integer scene, LocalDateTime callTime, List<DeliverAgainTaskDTO> deliverAgainTaskDTOList) {
        if(log.isInfoEnabled()) {
            log.info("检查的二次投放任务:{}", deliverAgainTaskDTOList);
        }
        List<DeliverAgainTaskDTO> result = new ArrayList<>();
        for (DeliverAgainTaskDTO deliverAgainTaskDTO:deliverAgainTaskDTOList) {
            // 条件列表之间的关系
            Integer logic = deliverAgainTaskDTO.getConditionRelation();
            // 投放任务条件
            List<JSONObject> conditions = deliverAgainTaskDTO.getConditions();
            if(log.isInfoEnabled()) {
                log.info("检查条件 conditions={}", conditions);
            }
            // 工单状态变更调用
            if(scene == 0 && ticketOnlyStatusAction(ticket, conditions, logic)) {
                result.add(deliverAgainTaskDTO);
            }
            if(scene == 1 && ticketFollowRecordAction(ticket, conditions, logic, callTime)) {
                result.add(deliverAgainTaskDTO);
            }
        }
        return result;
    }

    /**
     * 状态变更的操作，状态变更的调用场景，是没有提交跟进记录的。所以全部条件，存在跟进条件的不成立
     * @param ticket 工单
     * @param conditions 条件
     * @param logic 等于0全部条件成立；等于1表示任一条件成立
     * @return void
     * @author jy.zhao
     * @date 2021/8/24 18:48 
     **/
    private static boolean ticketOnlyStatusAction(Ticket ticket, List<JSONObject> conditions, Integer logic) {
        if(log.isInfoEnabled()) {
            log.info("开始检测工单状态变更是否成立，ticketId={}, conditions={}, logic={}", ticket.getId(), conditions, logic);
        }
        // 全部条件成立
        if(logic == Constants.TICKET_RULE_ALL_MATCH) {
            for(JSONObject condition:conditions) {
                // code等于0表示当前条件是检查工单的提交记录，1表示工单的状态变更
                Integer code = condition.getInteger("code");
                // 当前函数只有工单状态变更进行的调用，即不存在工单提交跟进记录，所以不成立
                if(Validator.isNull(code) || code == 0) {
                    return false;
                }
                if(code == 1 && !checkTicketStatus(ticket.getStatus(), condition)) {
                    return false;
                }
            }
            if(log.isInfoEnabled()) {
                log.info("logic=0 全部条件 都符合 工单状态检查，成立");
            }
            return true;
        }
        // 任一条件成立
        if(logic == Constants.TICKET_RULE_ONE_MATCH) {
            for(JSONObject condition:conditions) {
                Integer code = condition.getInteger("code");
                // code等于0表示当前条件是检查工单的提交记录，1表示工单的状态变更
                if(code == 0) {
                    // 当前函数只有工单状态变更进行的调用，即不存在工单提交跟进记录，因此该条件不对结果产生影响
                    continue;
                }
                if(code == 1 && checkTicketStatus(ticket.getStatus(), condition)) {
                    return true;
                }
            }
            if(log.isInfoEnabled()) {
                log.info("logic=1 任一条件 都不符合检查，不成立");
            }
            return false;
        }
        return false;
    }

    /**
     * 提交跟进记录的操作，检查跟进记录和状态变更
     * @param ticket 工单id
     * @param conditions 条件
     * @param logic 等于0全部条件成立；等于1表示任一条件成立
     * @param callTime 调用时间
     * @return boolean 是否通过
     * @author jy.zhao
     * @date 2021/8/24 19:20
     **/
    private boolean ticketFollowRecordAction(Ticket ticket, List<JSONObject> conditions, Integer logic, LocalDateTime callTime) {
        if(logic == Constants.TICKET_RULE_ALL_MATCH) {
            for(JSONObject condition:conditions) {
                Integer code = condition.getInteger("code");
                //  code等于0表示当前条件是检查工单的提交记录，1表示工单的状态变更
                if(code == 0) {
                    // 当前函数只有工单状态变更进行的调用，即不存在工单提交跟进记录，所以不成立
                    TicketRecord record = ticketRecordDao.findTicketFollowRecordByEvent(ticket.getId(), TicketRecordEventEnum.FOLLOWED.getIndex(), callTime);
                    if(Validator.isEmpty(record)) {
                        if(log.isInfoEnabled()) {
                            log.info("logic=0 工单跟进记录，条件不成立，没有新的更近记录");
                        }
                        return false;
                    }
                }
                if(code == 1 && !checkTicketStatus(ticket.getStatus(), condition)) {
                    if(log.isInfoEnabled()) {
                        log.info("logic=0 工单跟进记录，条件不成立，状态检查不对，status=={}, ticketId={}", condition.get(TICKET_STATUS), ticket.getId());
                    }
                    return false;
                }
            }
            if(log.isInfoEnabled()) {
                log.info("logic=0 工单跟进记录，成立");
            }
            return true;
        }
        // 任一条件成立
        if(logic == Constants.TICKET_RULE_ONE_MATCH) {
            for(JSONObject condition:conditions) {
                Integer code = condition.getInteger("code");
                // code等于0表示当前条件是检查工单的提交记录，1表示工单的状态变更
                if(code == 0) {
                    TicketRecord record = ticketRecordDao.findTicketFollowRecordByEvent(ticket.getId(), TicketRecordEventEnum.FOLLOWED.getIndex(), callTime);
                    if(Validator.isNotEmpty(record)) {
                        // logic=1 工单跟进记录，条件不成立，没有新的更近记录
                        return true;
                    }
                }
                if(code == 1 && checkTicketStatus(ticket.getStatus(), condition)) {
                    // logic=1 工单跟进记录，条件不成立，状态检查不对
                    return true;
                }
            }
            if(log.isInfoEnabled()) {
                log.info("logic=1 工单跟进记录，不成立");
            }
            return false;
        }
        return false;
    }

    /**
     * 检查当前工单状态
     * @param ticketStatus 工单状态
     * @param condition 符合要求的工单状态
     * @return boolean
     * @author jy.zhao
     * @date 2021/8/24 19:09 
     **/
    private static boolean checkTicketStatus(Integer ticketStatus, JSONObject condition) {
        if(condition.get(TICKET_STATUS) instanceof List) {
            JSONArray statusArray = condition.getJSONArray(TICKET_STATUS);
            return statusArray.contains(ticketStatus);
        } else if(condition.get(TICKET_STATUS) instanceof Integer) {
            Integer status = condition.getInteger(TICKET_STATUS);
            return ticketStatus.equals(status);
        }
        return false;
    }
}
